package com.dq.service.orders.impl;

import com.dq.context.event.user.StaffUserServiceEvent;
import com.dq.domain.sys.user.center.UserAccountStaffUser;
import com.dq.exception.customException.AdminException;
import com.dq.controller.in.request.ActivityOrderAdd;
import com.dq.controller.in.request.OrdersPayAdd;
import com.dq.controller.in.request.TakeItInCartRequest;
import com.dq.vo.baseVo.VO;
import com.dq.domain.activity.Activity;
import com.dq.domain.base.AbstractEntity;
import com.dq.domain.goods.Goods;
import com.dq.domain.goods.Product;
import com.dq.domain.goods.ShoppingBag;
import com.dq.domain.orders.Orders;
import com.dq.domain.orders.UserOrder;
import com.dq.domain.orders.info.OrderInfo;
import com.dq.domain.org.Org;
import com.dq.domain.record.ArrearsRecord;
import com.dq.domain.record.ProfitRecord;
import com.dq.domain.goods.stock.StockChangeRecord;
import com.dq.domain.sys.section.SysSection;
import com.dq.domain.sys.user.Integral;
import com.dq.domain.sys.user.user.base.SysUser;
import com.dq.domain.sys.user.user.WxUser;
import com.dq.repository.AllRepository;
import com.dq.service.ShiroService;
import com.dq.service.orders.OrdersService;
import com.dq.utils.RandomUtil;
import com.dq.utils.TimeUtil;
import org.apache.commons.lang3.RandomStringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @Author luchangtong
 * @Date 2019/11/27 15:27
 */
@Service
public class OrdersServiceImpl extends AllRepository implements OrdersService {
    @Autowired
    ShiroService shiroService;
    @Autowired
    ApplicationEventPublisher eventPublisher;

    private String generateNo() {
        String r;
        while (ordersRepository.existsByOrdersNo(r = System.currentTimeMillis() + RandomStringUtils.randomNumeric(16)))
            ;
        return r;
    }

    @Override
    @Transactional
    public UserOrder submitOrder(OrdersPayAdd ordersPayAdd, SysUser user, Long expressTime) throws AdminException {
        SysUser sysUser = shiroService.getUser();
        Goods goods =dao.get(Goods.class,ordersPayAdd.getGoodsId());
        if(ordersPayAdd.getNumber() == null){
            throw new AdminException("请选择数量");
        }
        Product product = productRepository.findByGoodsAndDeletedFalseAndIsDefaultTrue(goods);
        if(goodsService.productStock(product.getId(),sysUser.getSection().getId()) - ordersPayAdd.getNumber() < 0){
            throw new AdminException("库存不足");
        }
        UserOrder order = new UserOrder();
        if(ordersPayAdd.isFlag()){
            BigDecimal profitReturn = BigDecimal.ZERO;
            BigDecimal mayProfit = BigDecimal.ZERO;
            //返金
            if(ordersPayAdd.isProfitReturn()){
                BigDecimal sum = profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.add, ProfitRecord.ChangeProfitType.consume,user);
                profitReturn = sum.subtract(profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.less, ProfitRecord.ChangeProfitType.consume,user));
            }
            //可消费收益
            if(ordersPayAdd.isMayProfit()){
                BigDecimal accumulatedIncome = profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.add, ProfitRecord.ChangeProfitType.rakeBack,user);
                mayProfit = accumulatedIncome.subtract(profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.less, ProfitRecord.ChangeProfitType.rakeBack,user));
            }
            order.setOrdersPayCountDownTime(TimeUtil.formatFMT6Date(TimeUtil.minutesAddFMT_6(DateTime.now(),expressTime.intValue()).toString()));
            order.setOriginalPrice(goods.getOriginalPrice().multiply(new BigDecimal(ordersPayAdd.getNumber())));
            order.setDiscountPrice(profitReturn.add(mayProfit));
            order.setPrice(order.getOriginalPrice().subtract(order.getDiscountPrice()));
            order.setOrderSource(UserOrder.OrderSource.onLine);
            order.setStatus(UserOrder.UserOrderStatus.waitPay);
        }else {
            Long num = integralRepository.sumIntegralAdd(Integral.ChangeType.add,user) -integralRepository.sumIntegralAdd(Integral.ChangeType.less,user);
            if(goods.getIntegralNum()*ordersPayAdd.getNumber() > num){
                throw new AdminException("积分不足 不可购买");
            }
            order.setOriginalPrice(new BigDecimal("0"));
            order.setDiscountPrice(new BigDecimal("0"));
            order.setPrice(new BigDecimal("0"));
            order.setOrderSource(UserOrder.OrderSource.integral);
            order.setStatus(UserOrder.UserOrderStatus.waitCheckOut);
        }
        order.setOrg((Org) user.getSection());
        order.setOrdersNo(RandomUtil.getGenerateOrderNo(user.getId()));
        order.setRemark(ordersPayAdd.getRemark());
        order.setWxUser(user);
        order.setPayType(UserOrder.PayType.wxpay);
        order.setPayGoodsNum(ordersPayAdd.getNumber());
        order.setCateNum(1L);
        UserOrder userOrder = userOrderRepository.save(order);
        if(!ordersPayAdd.isFlag()){
            saveIntegral(ordersPayAdd,user,userOrder,goods);
        }
        OrderInfo orderInfo = new OrderInfo(order,product,ordersPayAdd.getNumber(),order.getPrice(),goods);
        OrderInfo orderInfoSave = orderInfoRepository.save(orderInfo);

        // 生成订单: 自动生成库存变动记录, 修改对应商品库存
        orgStockChangeService.orderInfo2Stock(userOrder.getOrg(), orderInfoSave, StockChangeRecord.ChangeDirection.reduce, StockChangeRecord.ChangeType.adjust);

        return order;
    }

    @Override
    public UserOrder.Vo takeItInCart(List<ShoppingBag> bags, Org org, String note, Long expressTime, TakeItInCartRequest takeItInCartRequest) throws AdminException {
        SysUser sysUser = shiroService.getUser();
        List<OrderInfo> infos = new ArrayList<>();
        bags.forEach(bag ->{
            try {
                if(goodsService.productStock(bag.getProduct().getId(),sysUser.getSection().getId()) - bag.getNumber() < 0){
                    throw new AdminException("库存不足");
                }
            } catch (AdminException e) {
                e.printStackTrace();
            }
            infos.add(bag.toOrderInfo());
        });
        shoppingBagRepository.deleteAll(bags);
        return takeIt(infos, org ,note, expressTime,takeItInCartRequest);
    }

    @Override
    @Transactional
    public UserOrder.Vo takeIt(List<OrderInfo> infos, Org org, String note, Long expressTime,TakeItInCartRequest takeItInCartRequest) throws AdminException {
        SysUser sysUser = shiroService.getUser();
        Long sum = 0L;
        BigDecimal originalPrice = BigDecimal.ZERO;
        for (OrderInfo orderInfo : infos) {
            sum += orderInfo.getNumber();
            originalPrice =  originalPrice.add(orderInfo.getAmount());
        }
        // 新增Order
        UserOrder userOrder = new UserOrder(generateNo(), note, org, sysUser, Orders.getOrdersPayCountDownTime(expressTime),sum,(long) infos.size());
        BigDecimal profitReturn = BigDecimal.ZERO;
        BigDecimal mayProfit = BigDecimal.ZERO;
        //返金
        if(takeItInCartRequest.isProfitReturn()){
            BigDecimal returnSum = profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.add, ProfitRecord.ChangeProfitType.consume,sysUser);
            profitReturn = returnSum.subtract(profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.less, ProfitRecord.ChangeProfitType.consume,sysUser));
        }
        //可消费收益
        if(takeItInCartRequest.isMayProfit()){
            BigDecimal accumulatedIncome = profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.add, ProfitRecord.ChangeProfitType.rakeBack,sysUser);
            mayProfit = accumulatedIncome.subtract(profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.less, ProfitRecord.ChangeProfitType.rakeBack,sysUser));
        }
        userOrder.setOrderSource(UserOrder.OrderSource.onLine);
        userOrder.setPayType(UserOrder.PayType.wxpay);
        userOrder.setOriginalPrice(originalPrice);
        userOrder.setDiscountPrice(profitReturn.add(mayProfit));
        userOrder.setPrice(userOrder.getOriginalPrice().subtract(userOrder.getDiscountPrice()));
        for (OrderInfo info : infos) {
            info.setOrders(userOrder);
            userOrder.amountAdd(info.getAmount());
            // 生成订单: 自动生成库存变动记录, 修改对应商品库存
            orgStockChangeService.orderInfo2Stock(userOrder.getOrg(), info, StockChangeRecord.ChangeDirection.reduce, StockChangeRecord.ChangeType.adjust);
        }
        ordersRepository.save(userOrder);
        orderInfoRepository.saveAll(infos);
        return (UserOrder.Vo) userOrder.toVO((List<OrderInfo.Vo>) VO.toVOCollection(infos));
    }

    @Override
    public UserOrder submitActivityOrder(Activity activity, SysUser user, Long expressTime, ActivityOrderAdd activityOrderAdd) throws AdminException {
        SysUser wxUser = dao.get(SysUser.class,activityOrderAdd.getWxUserId());
        if(wxUser == null){
            throw new AdminException("会员不存在");
        }
        SysSection sysSection = dao.get(SysSection.class,activityOrderAdd.getOrgId());
        if(sysSection == null){
            throw new AdminException("门店不存在");
        }
        UserOrder order = new UserOrder();
        order.setOrg((Org) sysSection);
        order.setOrdersNo(RandomUtil.getGenerateOrderNo(wxUser.getId()));
        order.setOrdersPayCountDownTime(TimeUtil.formatFMT6Date(TimeUtil.minutesAddFMT_6(DateTime.now(),expressTime.intValue()).toString()));
        order.setWxUser(wxUser);
        order.setOriginalPrice(activity.getNormalPrice());
        order.setPrice(order.getOriginalPrice().subtract(order.getDiscountPrice()));
        order.setOrderSource(UserOrder.OrderSource.activity);
        order.setStatus(UserOrder.UserOrderStatus.waitPay);
        order.setPayType(UserOrder.PayType.wxpay);
        UserOrder userOrder = userOrderRepository.save(order);
        OrderInfo orderInfo = new OrderInfo(order,activity,1L,order.getPrice());
        orderInfoRepository.save(orderInfo);
        return userOrder;
    }


    @Override
    public void takeItInStaffUserCart(List<ShoppingBag> bags, Org org, String note, Long expressTime, List<Long> staffUserIds, String giveProject, Long giveIntegral, Long wxUserId, Integer flag, BigDecimal arrearsPrice, BigDecimal discountPrice) {
        List<OrderInfo> infos = new ArrayList<>();
        BigDecimal sumPrice = BigDecimal.ZERO;
        for (ShoppingBag bag : bags) {
            infos.add(bag.toOrderInfo());
            sumPrice =sumPrice.add(bag.getProduct().getPrice().multiply(new BigDecimal(bag.getNumber().toString())));
            changeStock(bag);
        }
        shoppingBagRepository.deleteAll(bags);
        takeItStaffUser(infos, org ,note, expressTime,staffUserIds,giveProject,giveIntegral,wxUserId,flag,arrearsPrice,sumPrice,discountPrice);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void takeItStaffUser(List<OrderInfo> infos, Org org, String note, Long expressTime, List<Long> staffUserIds, String giveProject, Long giveIntegral, Long wxUserId, Integer flag, BigDecimal arrearsPrice, BigDecimal sumPrice, BigDecimal discountPrice) {
        SysUser user = sysUserService.getUser();

        WxUser wxUser = dao.get(WxUser.class,wxUserId);
        //积分余额
        Long num = integralRepository.sumIntegralAdd(Integral.ChangeType.add,wxUser) -integralRepository.sumIntegralAdd(Integral.ChangeType.less,wxUser)+giveIntegral;
        // 新增Order
        Boolean isOwed = false;
        BigDecimal price = BigDecimal.ZERO;
        if(flag == 1){
            isOwed = true;
            price = arrearsPrice;
        }
        Long sum = 0L;
        for (OrderInfo orderInfo : infos) {
            sum += orderInfo.getNumber();
        }
        UserOrder userOrder = new UserOrder(generateNo(), note, org, wxUser, Orders.getOrdersPayCountDownTime
                (expressTime),giveProject,num,isOwed,price,sum, (long) infos.size(),sumPrice,discountPrice);

        for (OrderInfo info : infos) {
            info.setOrders(userOrder);
            userOrder.amountAdd(info.getAmount());
        }
        userOrder.setPayType(UserOrder.PayType.wxpay);
        userOrder.setOrderSource(UserOrder.OrderSource.underLine);
        userOrder.setIsSettle(false);
        UserOrder order = userOrderRepository.save(userOrder);
        if(flag == 1){
            ArrearsRecord a = new ArrearsRecord();
            a.setArrearsNo(AbstractEntity.generyStrAndMstime(""));
            a.setSysUser(wxUser);
            a.setSysDept((Org) org);
            a.setOrders(order);
            a.setArrearsStatus(ArrearsRecord.ArrearsStatus.notPay);
            arrearsRecordRepository.save(a);
        }
        //判断下单人在不在staffUserIds中
        Boolean whether = false;
        if(staffUserIds != null) {
            for(Long id : staffUserIds){
                UserAccountStaffUser u = new UserAccountStaffUser();
//                u.setUserOrder(order);
//                u.setStaffUser(dao.get(SysUser.class,id));
                userOrderStaffUserRepository.save(u);
            };
        }
        if(!whether){
            UserAccountStaffUser u = new UserAccountStaffUser();
//            u.setUserOrder(order);
//            u.setStaffUser(user);
            userOrderStaffUserRepository.save(u);
        }

        orderInfoRepository.saveAll(infos);
        HashMap<String ,Object> map = new HashMap<>();
        map.put("order",userOrder);
        map.put("integral",giveIntegral);
        //分润 + 积分+提成
        // TODO  下单时不塞提成记录 改为一月统计一次总数
        eventPublisher.publishEvent(new StaffUserServiceEvent(map));
    }

    /**
     * 判断返金
     */
    public boolean consume(BigDecimal consume, SysUser user){
        //消费返金
        BigDecimal sum = profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.add, ProfitRecord.ChangeProfitType.consume,user);
        BigDecimal profitReturn = sum.subtract(profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.less, ProfitRecord.ChangeProfitType.consume,user));
        if(profitReturn.compareTo(consume) > -1){
            return true;
        }
        return false;
    }
    /**
     * 判断可消费收益
     */
    public boolean mayProfit(BigDecimal profitPrice, SysUser user){
        //累计收益
        BigDecimal accumulatedIncome = profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.add, ProfitRecord.ChangeProfitType.rakeBack,user);
        //可消费收益
        BigDecimal mayProfit = accumulatedIncome.subtract(profitRecordRepository.sumProfitRecordAdd(ProfitRecord.ProfitChangeType.less, ProfitRecord.ChangeProfitType.rakeBack,user));
        if(mayProfit.compareTo(profitPrice) > -1){
            return true;
        }
        return false;
    }


    public void saveIntegral(OrdersPayAdd ordersPayAdd, SysUser user, UserOrder userOrder, Goods goods){
        Integral i = new Integral();
        i.setUser(user);
        i.setCiType(Integral.ChangeIntegralType.goods);
        i.setChangeType(Integral.ChangeType.less);
        i.setChangeNum(goods.getIntegralNum()*ordersPayAdd.getNumber());
        i.setUserOrder(userOrder);
        integralRepository.save(i);
    }

    @Transactional(rollbackFor = Exception.class)
    public void changeStock(ShoppingBag bag)throws AdminException{
        StockChangeRecord s = new StockChangeRecord();
        SysUser sysUser = shiroService.getUser();
        s.setOrg(sysUser.getSection());
        s.setGoods(bag.getGoods());
        s.setProduct(bag.getProduct());
        s.setChangeType(StockChangeRecord.ChangeType.adjust);
        s.setStockStatus(StockChangeRecord.StockStatus.ApprovalSuccess);
        s.setChangeDirection(StockChangeRecord.ChangeDirection.reduce);
        s.setNum(bag.getNumber());
        StockChangeRecord stockChangeRecord = orgStockChangeService.saveStockChangeRecord(s, bag.getGoods(), bag.getProduct(), sysUser.getSection(), true);
    }

}
